package com.mofum.scope.common.utils;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

/**
 * @author yuyang@qxy37.com
 * @since 2019-03-19
 **/
public class ObjectUtils {

    public static <T> T obj2Object(Object data, Class<T> returnType) throws IllegalAccessException, InstantiationException {

        if (returnType == null) {
            throw new RuntimeException("returnType is required!");
        }

        if (data != null) {
            Field[] fields = returnType.getDeclaredFields();

            T t = returnType.newInstance();

            for (Field field : fields) {

                Field temp = null;
                Class<?> type = data.getClass();
                temp = ParentFieldUtils.getFieldByName(field.getName(), type);
                if (temp != null) {
                    field.setAccessible(true);
                    field.set(t, convertData(data, field));
                    field.setAccessible(false);
                }
            }
            return t;
        }

        return null;
    }

    private static Object convertData(Object data, Field field) throws IllegalAccessException {
        Field temp = ParentFieldUtils.getFieldByName(field.getName(), data.getClass());
        if (temp == null) {
            return null;
        }
        temp.setAccessible(true);
        Object returnData = temp.get(data);
        temp.setAccessible(false);
        return returnData;
    }

    public static <T> T map2Object(Map<String, ? extends Object> data, Class<T> returnType) throws IllegalAccessException, InstantiationException {

        if (returnType == null) {
            throw new RuntimeException("returnType is required!");
        }

        Set<String> set = data.keySet();

        if (set.size() > 0) {
            Field[] fields = returnType.getDeclaredFields();

            T t = returnType.newInstance();

            for (Field field : fields) {
                if (set.contains(field.getName())) {
                    field.setAccessible(true);
                    field.set(t, convertData(data, field));
                    field.setAccessible(false);
                }
            }
            return t;
        }

        return null;
    }

    private static Object convertData(Map<String, ? extends Object> data, Field field) {
        return data.get(field.getName());
    }

    public static <T> T toObject(Object data, Class<T> returnType) throws IllegalAccessException, NoSuchFieldException, InstantiationException {
        if (data instanceof Map) {
            return map2Object((Map<String, Object>) data, returnType);
        } else {
            return obj2Object(data, returnType);
        }
    }

}
